//
//  InstallLayerEMA.cpp
//  client
//
//  Created by galileoliu on 1/7/2019.
//
//

#include "InstallLayerEMA.h"

#include "AppDelegate.h"
#include "MessageDialog.h"
#include "ConfirmBox.h"
#include "UserDefaultKeys.h"
#include "NodePool.hpp"
#include "CCFactory.h"

#ifdef USE_EMACDN
#include "EmaOverseaSdkApi.hpp"
#endif

#include "crypto/CCCrypto.h"
extern "C" {
#include "crypto/base64/libbase64.h"
#include "crypto/md5.h"
}

USING_NS_CC;
using namespace cocos2d::extension;

static const std::string s_download_path = "/assets/";
static bool verifyAssetsPatch(const std::string& path, Manifest::Asset asset)
{
    bool ret = true;
    unsigned char buffer[extra::Crypto::MD5_BUFFER_LENGTH];
    extra::Crypto::MD5File(path.c_str(), buffer);
    string fileMD5(extra::Crypto::bin2hex(buffer, extra::Crypto::MD5_BUFFER_LENGTH));
    if (fileMD5 == asset.md5)
    {
        ret = true;
    }
    else
    {
        ret = false;
    }
    
    return ret;
}

template<typename ... Args>
std::string string_format( const std::string& format, Args ... args )
{
    size_t size = snprintf( nullptr, 0, format.c_str(), args ... ) + 1; // Extra space for '\0'
    std::unique_ptr<char[]> buf( new char[ size ] );
    snprintf( buf.get(), size, format.c_str(), args ... );
    return std::string( buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside
}

InstallLayerEMA::InstallLayerEMA():
InstallLayer()
,_newResourceVersion("")
,_downLoadTime(0)
#ifdef USE_EMACDN
,_cdnUrl("")
, _cdnUrlIndex(0)
,_waitMessageBox(false)
,_shouldStop(false)
,_flagShowPatchSizeDialog(false)
,_lastErrorCode(EventAssetsManagerEx::EventCode::ERROR_NONE)
,_curStage(AssetsManagerEx::State::UNCHECKED)
,_am(nullptr)
,_amListener(nullptr)
,_listener(nullptr)
#endif
{

}

InstallLayerEMA::~InstallLayerEMA()
{

}

// on "init" you need to initialize your instance
bool InstallLayerEMA::init()
{
    bool ret = InstallLayer::init();

    return ret;
}

#ifdef USE_EMACDN
void InstallLayerEMA::initAssetsManager()
{
    if (_cdnUrlList.size() > 0)
    {
        // Try every cdn url in sequence to ensure downloading successfully.
        _cdnUrl = _cdnUrlList[_cdnUrlIndex];
    }
    if(_cdnUrl.empty())
    {
        _cdnUrl = Configuration::getInstance()->getValue("CDNUpdateUrl").asString();
    }
    if (_cdnUrl.empty())
    {
        cocos2d::log("===>InstallLayerEMA: Cdn url is empty.");
        scheduleOnce([this](float){
            this->goNext();
        }, 0, "goNext");
        return;
    }
    log("===>InstallLayerEMA: Cdn url is %s", _cdnUrl.c_str());
    std::string localManifestUrl = Configuration::getInstance()->getValue("LocalManifestUrl").asString();
    std::string storagePath = AppDelegate::getStorePath() + s_download_path;
    
    _am = AssetsManagerEx::create(localManifestUrl, storagePath, _cdnUrl);
    _am->retain();
    _am->setVerifyCallback(verifyAssetsPatch);
}
#endif

void InstallLayerEMA::goStart()
{
    cocos2d::log("===>InstallLayerEMA::goStart()");
#ifdef USE_EMACDN
    setLoadingVisible(false);
    if (-1 == EmaOverseaSdkApi::getInitSdkState())
    {
        // 初始化sdk 还未返回结果
        _addSdkInitEventListener();
        updateStageLabel(_emaInfoString.GetUpdateInfoString(AssetsManagerEx::State::UNCHECKED));
    }
    else
    {
        _checkSdkInit();
    }
#endif
}

void InstallLayerEMA::goExit()
{
    cocos2d::log("===>InstallLayerEMA::goExit()");
#ifdef USE_EMACDN
    clear();
    _flagShowPatchSizeDialog = false;
#endif
}

void InstallLayerEMA::goNext()
{
    cocos2d::log("===>InstallLayerEMA::goNext()");
#ifdef USE_EMACDN
    clear();
    _flagShowPatchSizeDialog = false;
#endif
    
    if(_newResourceVersion.size() > 0)
    {
        _newResourceVersion = "";
        
        //坑啊一定注意 当资源发生变化一定要清除缓存
        //放到 AppDelegate::removeAllCache 方法里面了
        FileUtils::getInstance()->purgeCachedEntries();
        // 重新配置search path
        AppDelegate::setSearchPaths();
        // 重新加载语言包
        AppDelegate::loadL10NStr(true);
        
        runMainLua();
    }
    else
    {
        runMainLua();
    }
}

#ifdef USE_EMACDN

void InstallLayerEMA::_checkSdkInit(){
    if(EmaOverseaSdkApi::isInitialized())
    {
        _removeSdkInitEventListener();
        _onInitSdkSuccess();
    }
    else
    {
        CCLOG("===>InstallLayerEMA::_checkSdkInit() init sdk fail");
        _onInitSdkFail();
    }
}

// sdk 初始化成功 调用逻辑
void InstallLayerEMA::_onInitSdkSuccess()
{
    if(EmaOverseaSdkApi::isReview())
    {
        setLoadingVisible(false);
    }
    else
    {
        setLoadingVisible(true);
    }
    
    bool disableHotfix = true;
    Configuration* configuration = Configuration::getInstance();
    const Value& disableValue = configuration->getValue("DisableHotfix");
    if(!disableValue.isNull())
    {
        disableHotfix = disableValue.asBool();
    }
    if(disableHotfix)
    {
        scheduleOnce([this](float){
            this->goNext();
        }, 0, "goNext");
    }
    else
    {
        _cdnUrlList = EmaOverseaSdkApi::getCdnList();
        if (_cdnUrlList.size() == 0)
        {
            CCLOG("===>InstallLayerEMA: ERROR - SDK cdn url list is empty!");
        }
        else
        {
            ApplicationProtocol::Platform platform = Application::getInstance()->getTargetPlatform();
            std::string strPlatform = "";
            switch (platform)
            {
            case ApplicationProtocol::Platform::OS_ANDROID:
                strPlatform = "android/";
                break;
            case ApplicationProtocol::Platform::OS_IPHONE:
            case ApplicationProtocol::Platform::OS_IPAD:
                strPlatform = "ios/";
                break;
            case ApplicationProtocol::Platform::OS_MAC:
                strPlatform = "mac/";
                break;
            case ApplicationProtocol::Platform::OS_WINDOWS:
                strPlatform = "windows/";
                break;
            default:
                break;
            }
            for (auto iter = _cdnUrlList.begin(); iter != _cdnUrlList.end(); iter++)
            {
                *iter += strPlatform;
            }
        }
        initAssetsManager();
        updateStageLabel(_emaInfoString.GetUpdateInfoString(_am->getState()));
        startUpdate(this);
    }
}

// sdk 初始化失败 弹出 网络连接失败
void InstallLayerEMA::_onInitSdkFail()
{
   // 网络连接失败  重试 退出游戏
    MessageDialog* dialog = MessageDialog::create();
//    dialog->setTwoButton(true);
    dialog->setMessage(Localization::getInstance()->getStr("NetworkErrorWithRetry").c_str());
    dialog->setConfirmButton(Localization::getInstance()->getStr("CommonBtnRetry").c_str());
    dialog->setCancelButtonStr(Localization::getInstance()->getStr("CommonBtnExitGame").c_str());
    dialog->setConfirmCallback([this](MessageDialog* sender){
        _waitMessageBox = false;
        CCLOG("===>InstallLayerEMA::_onInitSdkFail() ConfirmCallback retry init sdk");
        this->_addSdkInitEventListener();
        sender->removeFromParent();
        EmaOverseaSdkApi::initSdk();
    });
    dialog->setCancelCallback([this](MessageDialog* sender){
        _waitMessageBox = false;
        this->stopUpdate();
        sender->removeFromParent();
        Director::getInstance()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
        exit(0);
#endif
    });
    this->addChild(dialog);
    _waitMessageBox = true;
}

void InstallLayerEMA::_addSdkInitEventListener()
{
    if(_listener == nullptr)
    {
        CCLOG("===>InstallLayerEMA::_addSdkInitEventListener()");
        _listener = Director::getInstance()->getEventDispatcher()->addCustomEventListener("CHANNEL_INIT_EVENT", [this](cocos2d::EventCustom* event){
            this->_checkSdkInit();
        });
    }
}

void InstallLayerEMA::_removeSdkInitEventListener()
{
    if(_listener != nullptr)
    {
        CCLOG("===>InstallLayerEMA::_removeSdkInitEventListener()");
        Director::getInstance()->getEventDispatcher()->removeEventListener(_listener);
        _listener = nullptr;
    }
}

void InstallLayerEMA::startUpdate(cocos2d::Ref* sender)
{
    if (!_am->getLocalManifest()->isLoaded())
    {
        CCLOG("===>InstallLayerEMA: Fail to update assets, step skipped.");
        goNext();
    }
    else
    {
        _amListener = EventListenerAssetsManagerEx::create(_am, [this](EventAssetsManagerEx* event){
            static int failCount = 0;
            switch (event->getEventCode())
            {
            case EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST:
            case EventAssetsManagerEx::EventCode::ERROR_DOWNLOAD_MANIFEST:
            case EventAssetsManagerEx::EventCode::ERROR_PARSE_MANIFEST:
                {
                    onError(_am->getState(), event->getEventCode());
                    EmaOverseaSdkApi::reportActiveBuriedPoint("dc_download_finish", 1);
                }
                break;
            case EventAssetsManagerEx::EventCode::START_DOWNLOAD_MANIFEST:
                {
                    CCLOG("===>InstallLayerEMA: Start downloading manifest.");
                    EmaOverseaSdkApi::reportActiveBuriedPoint("dc_download_manifest_start", 0);
                }
                break;
            case EventAssetsManagerEx::EventCode::DOWNLOAD_MANIFEST_FINISHED:
                {
                    CCLOG("===>InstallLayerEMA: Finish downloading manifest.");
                    EmaOverseaSdkApi::reportActiveBuriedPoint("dc_download_manifest_finish", 0);
                }
                break;
            case EventAssetsManagerEx::EventCode::NEW_VERSION_FOUND:
                {
                    if (_flagShowPatchSizeDialog == false)
                    {
                        float patchSize = _am->getPatchSize();
                        std::string extraMsg = StringUtils::format("%.2fMB", patchSize / (1024 * 1024));
                        std::string msgStr = _emaErrorString.getUpdateErrorString(EventAssetsManagerEx::EventCode::NEW_VERSION_FOUND, extraMsg);
                        MessageDialog* dialog = MessageDialog::create();
//                        dialog->setTwoButton(true);
                        dialog->setMessage(msgStr.c_str());
                        dialog->setConfirmButton(_emaInfoString.GetUpdateMsgBoxBtnString(EMAInfoString::MessageBoxBtnType::Confirm).c_str());
                        dialog->setCancelButtonStr(_emaInfoString.GetUpdateMsgBoxBtnString(EMAInfoString::MessageBoxBtnType::Cancel).c_str());
                        dialog->setConfirmCallback([this](MessageDialog* sender){
                            _waitMessageBox = false;
                            _am->startUpdate();
                            this->setResourceVersion(Application::getInstance()->getRemoteResourceVersion());
                            sender->removeFromParent();
                            _downLoadTime = cocos2d::utils::gettime();
                            EmaOverseaSdkApi::reportActiveBuriedPoint("dc_download_request", 0);
                        });
                        dialog->setCancelCallback([this](MessageDialog* sender){
                            _waitMessageBox = false;
                            _am->destroyTempFile();
                            this->stopUpdate();
                            sender->removeFromParent();
                            Director::getInstance()->end();
    #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
                            exit(0);
    #endif
                        });
                        this->addChild(dialog);
                        EmaOverseaSdkApi::reportActiveBuriedPoint("dc_download_patch_dialog_show", 0);
                        _waitMessageBox = true;
                        _flagShowPatchSizeDialog = true;
                    }
                    else
                    {
                        _am->startUpdate();
                        this->setResourceVersion(Application::getInstance()->getRemoteResourceVersion());
                    }
                }
                break;
            case EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION:
                {
                    std::string assetId = event->getAssetId();
                    float percent = event->getPercent();
                    std::string str;
                    if (assetId == AssetsManagerEx::VERSION_ID)
                    {
                        str = StringUtils::format("Version file: %.2f", percent) + "%";
                    }
                    else if (assetId == AssetsManagerEx::MANIFEST_ID)
                    {
                        str = StringUtils::format("Manifest file: %.2f", percent) + "%";
                    }
                    else
                    {
                        str = StringUtils::format("Asset file [%s]: %.2f", assetId.c_str(), percent) + "%";
                    }
                    CCLOG("===>InstallLayerEMA: Updating %s", str.c_str());
                    int64_t totalSize = event->getTotalBytesExpected();
                    int64_t nowSize = event->getTotalBytesReceived();
                    onProgress(_am->getState(), percent, totalSize, nowSize);
                }
                break;
            case EventAssetsManagerEx::EventCode::START_UNZIP:
                {
                    CCLOG("===>InstallLayerEMA: Start unzip patches.");
                    double curTime = cocos2d::utils::gettime();
                    int duration = 0;
                    if(_downLoadTime != 0){
                        duration = (int)(curTime - _downLoadTime);
                    }
                    EmaOverseaSdkApi::reportActiveBuriedPoint("dc_download_finish", 0, duration);
                    EmaOverseaSdkApi::reportActiveBuriedPoint("dc_update_start", 0);
                }
                break;
            case EventAssetsManagerEx::EventCode::ALREADY_UP_TO_DATE:
            case EventAssetsManagerEx::EventCode::UPDATE_FINISHED:
                {
                    CCLOG("===>InstallLayerEMA: Update finished. %s", event->getMessage().c_str());
                    onUpdateSuccess();
                    EmaOverseaSdkApi::reportActiveBuriedPoint("dc_update_finish", 0);
                }
                break;
            case EventAssetsManagerEx::EventCode::UPDATE_FAILED:
                {
                    failCount++;
                    CCLOG("===>InstallLayerEMA: Update failed. %s Try time count is %d.", event->getMessage().c_str(), failCount);
                    if (failCount < 5)
                    {
                        _am->downloadFailedAssets();
                    }
                    else
                    {
                        CCLOG("===>InstallLayerEMA: Reach maximum fail count, exit update process");
                        failCount = 0;
                        EmaOverseaSdkApi::reportActiveBuriedPoint("dc_update_finish", 1);
                        onError(_am->getState(), event->getEventCode());
                    }
                }
                break;
            case EventAssetsManagerEx::EventCode::ERROR_UPDATING:
            case EventAssetsManagerEx::EventCode::ERROR_DECOMPRESS:
            case EventAssetsManagerEx::EventCode::ERROR_APP_UPDATE:
                onError(_am->getState(), event->getEventCode(), event);
                break;
            default:
                break;
            }
        });
        Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(_amListener, 1);

        updateStageLabel(_emaInfoString.GetUpdateInfoString(_am->getState()));
        
        scheduleOnce([this](float){
            if (_am != nullptr)
            {
                _am->update();
                updateStageLabel(_emaInfoString.GetUpdateInfoString(_am->getState()));
            }
        }, 0, "hotUpdate");
    }
}

void InstallLayerEMA::update(float dt)
{
    if (_am == nullptr)
    {
        return;
    }
    _speedCounter.speedCounter(dt);
    if (_waitMessageBox)
    {
        return;
    }
    if(_lastErrorCode == EventAssetsManagerEx::EventCode::ERROR_NONE)
    {
        if(_updateSuccess)
        {
            _updateSuccess = false;
            if (_newResourceVersion.size() > 0)
            {
                AppDelegate::setResourceVersion(_newResourceVersion);
            }
            goNext();
        }
        else if (_am->getState() == AssetsManagerEx::State::PREDOWNLOAD_MANIFEST)
        {
            std::string msg = _emaInfoString.GetUpdateInfoString(AssetsManagerEx::State::PREDOWNLOAD_MANIFEST);
            static int tempCount = 0;
            static float tempDelta = 0.0f;
            if (tempDelta == 0.0f)
            {
                switch (tempCount)
                {
                case 1:
                    msg = msg + ".";
                    break;
                case 2:
                    msg = msg + "..";
                    break;
                case 3:
                    msg = msg + "...";
                    break;
                default:
                    break;
                }
                tempCount = tempCount + 1;
                if (tempCount > 3)
                {
                    tempCount = 0;
                }
                updateStageLabel(msg);
            }
            tempDelta = tempDelta + dt;
            if (tempDelta > 1.0f)
            {
                tempDelta = 0.0f;
            }
        }
    }
}

EMAInfoString& InstallLayerEMA::getEMAInfoString()
{
    return _emaInfoString;
}

std::string InstallLayerEMA::getDownSizeShowString(int64_t totalSize, int64_t nowSize)
{
    if (totalSize == 0)
    {
        return "[-/-]";
    }
    else if (totalSize < 1024 * 1024)
    {
        float tl = (float)(totalSize) / 1024;
        float ns = (float)(nowSize) / 1024;
        return StringUtils::format("[%.2fKB/%.2fKB]", ns, tl);
    }
    else
    {
        float tl = (float)(totalSize) / (1024 * 1024);
        float ns = (float)(nowSize) / (1024 * 1024);
        return StringUtils::format("[%.2fMB/%.2fMB]", ns, tl);
    }
}

void InstallLayerEMA::onProgress(AssetsManagerEx::State curStage, float percent, int64_t totalSize, int64_t nowSize)
{
    cocos2d::log("===>InstallLayerEMA::OnProgress curStage:%d totalSize:%lld nowSize:%lld",(int)curStage, totalSize, nowSize);
    
    if(_shouldStop)
    {
        return ;
    }
    
    if(curStage != _curStage)
    {
        _speedCounter.stopSpeedCounter();
    }
    
    std::string msg = _emaInfoString.GetUpdateInfoString(curStage);
    if (percent >= 0)
    {
        int p = static_cast<int>(percent);
        if (curStage == AssetsManagerEx::State::DOWNLOADING_VERSION
            || curStage == AssetsManagerEx::State::DOWNLOADING_MANIFEST
            || curStage == AssetsManagerEx::State::UPDATING)
        {
            msg = msg + " " + getDownSizeShowString(totalSize, nowSize);
            if (curStage != _curStage)
            {
                _curStage = curStage;
                _speedCounter.startSpeedCounter();
            }
            _speedCounter.setSize((size_t)nowSize);
            updateProgressLabel(StringUtils::format("%d%%(%.1fKB/s)",p,_speedCounter.getSpeed()/1024.0f));
        }
        else
        {
            updateProgressLabel(StringUtils::format("%d%%",p));
        }
        updateProgressBar(p);
    }
    else
    {
        updateProgressBar(0);
    }

    updateStageLabel(msg);
}

void InstallLayerEMA::onError(AssetsManagerEx::State curStage, EventAssetsManagerEx::EventCode errorCode, EventAssetsManagerEx* event)
{
    if(_shouldStop)
    {
        return ;
    }
    
    _lastErrorCode = errorCode;
    MessageDialog* dialog = nullptr;
    string extraErrorMsg = "";
    switch (errorCode)
    {
    case EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST:
        {
            CCLOG("===>InstallLayerEMA: No local manifest file found, skip assets update.");
            dialog = MessageDialog::create();
            dialog->setConfirmButton(_emaInfoString.GetUpdateMsgBoxBtnString(EMAInfoString::MessageBoxBtnType::Confirm).c_str());
            dialog->setConfirmCallback([this](MessageDialog* sender){
                _waitMessageBox = false;
                // TODO: Download primary project.manifest from server.
                this->stopUpdate();
                sender->removeFromParent();
                Director::getInstance()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
                exit(0);
#endif
            });
        }
        break;
    case EventAssetsManagerEx::EventCode::ERROR_DOWNLOAD_MANIFEST:
        {
            CCLOG("===>InstallLayerEMA: Fail to download manifest file, skip assets update.");
            dialog = MessageDialog::create();
            dialog->setConfirmButton(_emaInfoString.GetUpdateMsgBoxBtnString(EMAInfoString::MessageBoxBtnType::Retry).c_str());
            dialog->setConfirmCallback([this](MessageDialog* sender){
                _waitMessageBox = false;
                this->continueUpdate();
                sender->removeFromParent();
            });
        }
        break;
    case EventAssetsManagerEx::EventCode::ERROR_PARSE_MANIFEST:
        {
            CCLOG("===>InstallLayerEMA: Fail to parse remote manifest file, skip assets update.");
            dialog = MessageDialog::create();
            dialog->setConfirmButton(_emaInfoString.GetUpdateMsgBoxBtnString(EMAInfoString::MessageBoxBtnType::Retry).c_str());
            dialog->setConfirmCallback([this](MessageDialog* sender){
                _waitMessageBox = false;
                this->continueUpdate();
                sender->removeFromParent();
            });
        }
        break;
    case EventAssetsManagerEx::EventCode::UPDATE_FAILED:
        {
            CCLOG("===>InstallLayerEMA: Update failed.");
            dialog = MessageDialog::create();
            dialog->setConfirmButton(_emaInfoString.GetUpdateMsgBoxBtnString(EMAInfoString::MessageBoxBtnType::Retry).c_str());
            dialog->setConfirmCallback([this](MessageDialog* sender){
                _waitMessageBox = false;
                this->continueUpdate();
                sender->removeFromParent();
            });
        }
        break;
    case EventAssetsManagerEx::EventCode::ERROR_UPDATING:
        {
            extraErrorMsg = string_format("[%s]:(%s)", event->getAssetId().c_str(), event->getMessage().c_str());
            CCLOG("===>InstallLayerEMA: Fail to update asset[%s]. Msg(%s) CurlECode(%d) CurlMCode(%d).",
                  event->getAssetId().c_str(), event->getMessage().c_str(), event->getCURLECode(), event->getCURLMCode());
//            dialog = MessageDialog::create();
//            dialog->setConfirmButton(_emaInfoString.GetUpdateMsgBoxBtnString(EMAInfoString::MessageBoxBtnType::Retry).c_str());
//            dialog->setConfirmCallback([this](MessageDialog* sender){
//                _waitMessageBox = false;
//                this->continueUpdate();
//                sender->removeFromParent();
//            });
        }
        break;
    case EventAssetsManagerEx::EventCode::ERROR_DECOMPRESS:
        {
            extraErrorMsg = string_format("[%s]:(%s)", event->getAssetId().c_str(), event->getMessage().c_str());
            CCLOG("===>InstallLayerEMA: Fail to decompress asset[%s]. Msg(%s).", event->getAssetId().c_str(), event->getMessage().c_str());
            dialog = MessageDialog::create();
            dialog->setConfirmButton(_emaInfoString.GetUpdateMsgBoxBtnString(EMAInfoString::MessageBoxBtnType::Confirm).c_str());
            dialog->setConfirmCallback([this](MessageDialog* sender){
                _waitMessageBox = false;
                // TODO: Download primary project.manifest from server.
                this->stopUpdate();
                sender->removeFromParent();
                Director::getInstance()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
                exit(0);
#endif
            });
        }
        break;
    case EventAssetsManagerEx::EventCode::ERROR_APP_UPDATE:
        {
            CCLOG("===>InstallLayerEMA: Need application update.");
            // Guide user to get new app in store.
            dialog = MessageDialog::create();
            dialog->setConfirmButton(_emaInfoString.GetUpdateMsgBoxBtnString(EMAInfoString::MessageBoxBtnType::Go).c_str());
            dialog->setConfirmCallback([this](MessageDialog* sender){
                _waitMessageBox = false;
                // Go to app store.
                this->stopUpdate();
                sender->removeFromParent();
                EmaOverseaSdkApi::jumpToAppShop();
                // Exit app.
                Director::getInstance()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
                exit(0);
#endif
            });
        }
        break;
    default:
        break;
    }
    
    // Show error dialog.
    if (dialog != nullptr)
    {
        std::string errorStr = _emaErrorString.getUpdateErrorString(_lastErrorCode, extraErrorMsg);
        dialog->setMessage(errorStr.c_str());
        
        this->addChild(dialog);
        
        _waitMessageBox = true;

        _lastErrorCode = EventAssetsManagerEx::EventCode::ERROR_NONE;
    }
}

void InstallLayerEMA::onUpdateSuccess()
{
    if(_shouldStop)
    {
        return ;
    }
    
    cocos2d::log("===>InstallLayerEMA::OnUpdateSuccess()");
    
    _updateSuccess = true;
    _lastErrorCode = EventAssetsManagerEx::EventCode::ERROR_NONE;

    updateStageLabel(_emaInfoString.GetUpdateInfoString(AssetsManagerEx::State::UP_TO_DATE));
    updateProgressLabel("");
}

void InstallLayerEMA::continueUpdate()
{
    // Start downloading with another url.
    clear();
    
    _cdnUrlIndex++;
    if (_cdnUrlIndex >= _cdnUrlList.size())
    {
        _cdnUrlIndex = 0;
    }
    
    scheduleOnce([this](float){
        this->initAssetsManager();

        this->updateStageLabel(_emaInfoString.GetUpdateInfoString(_am->getState()));
        
        this->startUpdate(this);
    }, 0, "continueUpdate");
}

void InstallLayerEMA::stopUpdate()
{
    _speedCounter.stopSpeedCounter();
    
    goExit();
}

void InstallLayerEMA::clear()
{
    _removeSdkInitEventListener();
    if (_amListener)
    {
        Director::getInstance()->getEventDispatcher()->removeEventListener(_amListener);
        _amListener = nullptr;
    }
    if (_am)
    {
        _am->release();
        _am = nullptr;
    }
}

void InstallLayerEMA::setResourceVersion(const std::string& version)
{
    _newResourceVersion = version;
}

#endif
